package com.ant.storage.service.impl;

import com.ant.storage.common.ResultCode;
import com.ant.storage.common.ResultVo;
import com.ant.storage.dto.PickingDto;
import com.ant.storage.handler.AntException;
import com.ant.storage.mapper.CarInventoryMapper;
import com.ant.storage.mapper.CarPickingMapper;
import com.ant.storage.pojo.*;
import com.ant.storage.service.*;
import com.ant.storage.utils.RandomUtil;
import com.ant.storage.vo.PickingCommodityVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletContext;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author melon
 * @since 2024-01-04
 */
@Service
public class CarPickingServiceImpl extends ServiceImpl<CarPickingMapper, CarPicking> implements ICarPickingService {

    @Autowired
    ICarPickingDetailsService pickingDetailsService;

    @Autowired
    ICarPickingService pickingService;

    @Autowired
    ICarInventoryService inventoryService;

    @Autowired
    ICarInventoryLogService inventoryLogService;

    @Autowired
    CarInventoryMapper inventoryMapper;

    @Autowired
    public ServletContext servletContext;

    @Autowired
    IDepartmentService departmentService;

    @Override
    public PageInfo<CarPicking> querylist(PickingDto dto) {

        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        if (userInfo == null) {
            throw new AntException(ResultCode.FAILURE.getCode(), "登录超时");
        }
        PageHelper.startPage(dto.getPageIndex(), dto.getPageSize());
        QueryWrapper<CarPicking> wrapper = new QueryWrapper<>();

        if (dto.getWarehouseId() != null) {
            wrapper.in("warehouse_id", dto.getWarehouseId());
        }
        if (StringUtils.isNotEmpty(dto.getOddNumbers())) {
            wrapper.eq("odd_numbers", dto.getOddNumbers());
        }
        if (StringUtils.isNotEmpty(dto.getBusinessOrderNumber())) {
            wrapper.eq("business_order_number", dto.getBusinessOrderNumber());
        }
        if (StringUtils.isNotEmpty(dto.getStatus())) {
            wrapper.eq("status", dto.getStatus());
        }
        if (StringUtils.isNotEmpty(dto.getDepId())) {
            wrapper.eq("dep_id", dto.getDepId());
        }
        if (dto.getCollectionType() != null) {
            wrapper.eq("collection_type", dto.getCollectionType());
        }
        if (dto.getAuditStatus() != null) {
            wrapper.eq("audit_status", dto.getAuditStatus());
        }
        if (dto.getTimes() != null && dto.getTimes().size() != 0) {
            wrapper.ge("delivery_time", dto.getTimes().get(0) + " 00:00:00");
            wrapper.le("delivery_time", dto.getTimes().get(1) + " 23:59:59");
        }
        if (userInfo.getRoles() == null) {
            wrapper.lambda().in(CarPicking::getUserId, userInfo.getNameId());
        }
        if (userInfo.getRoles() != null && userInfo.getRoles().equals("admin")) {
            wrapper.lambda().in(CarPicking::getCityId, userInfo.getCityId());
        }
        if (userInfo.getRoles() != null && userInfo.getRoles().equals("warehouse")) {
            wrapper.lambda().in(CarPicking::getUserId, userInfo.getNameId())
                    .or().in(CarPicking::getCityId, userInfo.getCityId());
        }
        if (userInfo.getRoles() != null && userInfo.getRoles().equals("price")) {
            wrapper.lambda().in(CarPicking::getUserId, userInfo.getNameId());
        }
        wrapper.eq("is_delete", 1);
        wrapper.orderByDesc("id");
        List<CarPicking> pickingList = this.baseMapper.selectList(wrapper);
        pickingList.stream().map(item -> {
            //查詢商品
            List<PickingCommodityVo> PickingDetails = this.baseMapper.findByIdList(item.getId());
            item.setDetailsList(PickingDetails);
            return item;
        }).collect(Collectors.toList());
        PageInfo<CarPicking> pageInfo = new PageInfo<>(pickingList);
        return pageInfo;

    }

    @Override
    public CarPicking getPickingByID(Integer id) {
        CarPicking pickingList = this.baseMapper.selectOne(new QueryWrapper<CarPicking>().eq("id", id));
        if (pickingList == null) {
            throw new AntException(ResultCode.NOT_FOUND);
        }
        //查詢商品
        List<PickingCommodityVo> PickingDetails = this.baseMapper.findByIdList(pickingList.getId());
        pickingList.setDetailsList(PickingDetails);
        return pickingList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo savePicking(CarPicking picking) throws NullPointerException, IOException {
        synchronized (this) {
            picking.setOddNumbers("NL" + RandomUtil.getOrderNumbers(this.baseMapper.selectLastID()));
            picking.setCreationTime(new Date());
            picking.setIsDelete(1);
            this.baseMapper.insert(picking);
            if (picking.getDetailsList().size() > 0) {
                picking.getDetailsList().stream().map(item -> {
                    CarPickingDetails details = new CarPickingDetails();
                    details.setId(item.getId());
                    details.setInventoryId(item.getInventoryId());
                    details.setPickingId(picking.getId());
                    details.setActualQuantity(item.getActualQuantity() == "0" || item.getActualQuantity() == null ?
                            null : item.getApplyNumber());
                    details.setApplyNumber(item.getApplyNumber() == "0" || item.getApplyNumber() == null ? null :
                            item.getApplyNumber());
                    details.setPrice(item.getCommodityPrice());
                    details.setIsDelete(1);
                    pickingDetailsService.save(details);
                    return details;
                }).collect(Collectors.toList());
                BigDecimal reduce = picking.getDetailsList().stream().map(p ->
                        p.getGoodsPrice().multiply(new BigDecimal(p.getActualQuantity() == null ? "0" :
                                p.getActualQuantity())))
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                pickingService.update(new UpdateWrapper<CarPicking>().set("price", reduce).eq("id", picking.getId()));
                return ResultVo.success("保存成功");
            } else {
                throw new AntException(ResultCode.PARAM_IS_BLANK);
            }
        }
    }

    @Override
    public ResultVo pickingComplete(CarPicking picking) {
        synchronized (this) {
            CarPicking pickingServiceOne = pickingService.getOne(new QueryWrapper<CarPicking>()
                    .eq("id", picking.getId()).eq("is_delete", 1));
            if (pickingServiceOne != null && picking.getDetailsList().size() > 0) {
                picking.getDetailsList().stream().map(item -> {
                    CarPickingDetails details = new CarPickingDetails();
                    details.setId(item.getId());
                    details.setInventoryId(item.getInventoryId());
                    details.setPickingId(picking.getId());
                    details.setActualQuantity(item.getActualQuantity() == "0" || item.getActualQuantity() == "" ? "" :
                            item.getActualQuantity());
                    details.setApplyNumber(item.getApplyNumber() == "0" || item.getApplyNumber() == "" ? "" :
                            item.getApplyNumber());
                    details.setPrice(item.getCommodityPrice());
                    pickingDetailsService.updateById(details);
                    return details;
                }).collect(Collectors.toList());

                BigDecimal reduce = picking.getDetailsList().stream().map(p ->
                        p.getCommodityPrice().multiply(new BigDecimal(p.getActualQuantity() == null || p.getActualQuantity() == "" ? "0" :
                                p.getActualQuantity())))
                        .reduce(BigDecimal.ZERO, BigDecimal::add);

                pickingService.update(new UpdateWrapper<CarPicking>().set("price", reduce)
                        .set("status", picking.getStatus())
                        .set("creation_by", picking.getCreationBy())
                        .set("delivery_time", new Date())
                        .eq("id", picking.getId()));

                if (picking.getStatus().equals("2")) {

                    List<CarPickingDetails> pickingDetails = pickingDetailsService.list(new QueryWrapper<CarPickingDetails>()
                            .eq("picking_id", picking.getId()).eq("is_delete", 1));
                    pickingDetails.stream().map(item -> {
                        boolean b = verifyInventory(item.getInventoryId(), new BigDecimal(item.getActualQuantity()));
                        if (b) {
                            CarInventory one = inventoryService.getOne(new QueryWrapper<CarInventory>().eq("id",
                                    item.getInventoryId()));
                            BigDecimal amout =
                                    one.getGoodsAmount().subtract(new BigDecimal(item.getActualQuantity()));
                            amout.setScale(2, BigDecimal.ROUND_HALF_UP);
                            inventoryService.update(new UpdateWrapper<CarInventory>()
                                    .set("goods_amount", amout)
                                    .eq("id", item.getInventoryId()));
                            CarInventoryLog log = new CarInventoryLog();
                            log.setWarehouseId(one.getWarehouseId());
                            log.setInventoryId(item.getInventoryId());
                            log.setGoodsAmount(item.getActualQuantity() == "0" || item.getActualQuantity() == "" ?
                                    null : item.getActualQuantity());
                            log.setGoodsPrice(item.getPrice());
                            log.setStockState(2);
                            log.setSubscribeId(picking.getId());
                            log.setRemark("领料出库");
                            log.setCreatorBy(picking.getCreationBy());
                            log.setCreationTime(new Date());
                            inventoryLogService.save(log);
                            return item;
                        } else {
                            String commodityName =  inventoryMapper.selectCommodityName(item.getInventoryId());
                            throw new AntException(ResultCode.FAILURE.getResultCode(), commodityName + "，存不足无法出库!");
                        }
                    }).collect(Collectors.toList());
                    return ResultVo.success("操作成功");
                }
                return ResultVo.success("操作成功");
            }
            return ResultVo.fail("领料单不存在");
        }
    }


    //判断库存是否为0
    public boolean verifyInventory(Integer id, BigDecimal number) {
        CarInventory one = inventoryService.getOne(new QueryWrapper<CarInventory>().eq("id", id));
        if (one != null) {
            if (one.getGoodsAmount().subtract(number).compareTo(BigDecimal.ZERO) < 0) {
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    }
}
